/*
 * Copyright (c) 2023, mdf Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2023-10-18     MacRsh       First version
 */

#ifndef MDF_SERVICE_H
#define MDF_SERVICE_H

#include "inc/mdf_def.h"

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

//#define MDF_ASSERT(ex) \
//    do{                \
//        if(!(ex))       \
//        {       \
//            printf("%s,%d\r\n",__FILE__,__LINE__);\
//        }\
//    }while(0)

#define MDF_ASSERT(ex) do{if(!(ex)) {printf("%s [%s]\r\n", #ex, (__FUNCTION__));while(1);}}while(0)

/**
 * @brief This macro function gets its structure from its member.
 *
 * @param pointer The pointer to the structure.
 * @param type The type of the structure.
 * @param member The member of the structure.
 *
 * @return A pointer to the structure.
 */
#define mdf_container_of(pointer, type, member) \
    ((type *)((char *)(pointer) - (unsigned long)(&((type *)0)->member)))

/**
 * @brief This macro function gets the number of elements in an array.
 *
 * @param array The array.
 *
 * @return The number of elements in the array.
 */
#define mdf_array_num(array)            (sizeof(array)/sizeof(array[0]))

/**
 * @brief This macro function checks if a list is empty.
 *
 * @param list The list to check.
 *
 * @return True if the list is empty, mdf_false otherwise.
 */
#define mdf_list_is_empty(list)         (((list)->next) == (list))

/**
* @brief This function initialize a double list.
*
* @param list The list to initialize.
*/
MDF_INLINE void mdf_list_init(struct mdf_list *list)
{
    list->next = list;
    list->prev = list;
}

/**
 * @brief This function insert a node after a node in a double list.
 *
 * @param list The list to insert after.
 * @param node The node to insert.
 */
MDF_INLINE void mdf_list_insert_after(struct mdf_list *list, struct mdf_list *node)
{
    list->next->prev = node;
    node->next = list->next;
    list->next = node;
    node->prev = list;
}

/**
 * @brief This function insert a node before a node in a double list.
 *
 * @param list The list to insert before.
 * @param node The node to insert.
 */
MDF_INLINE void mdf_list_insert_before(struct mdf_list *list, struct mdf_list *node)
{
    list->prev->next = node;
    node->prev = list->prev;
    list->prev = node;
    node->next = list;
}

/**
 * @brief This function remove a node from a double list.
 *
 * @param node The node to remove.
 */
MDF_INLINE void mdf_list_remove(struct mdf_list *node)
{
    node->next->prev = node->prev;
    node->prev->next = node->next;
    node->next = node->prev = node;
}

/**
 * @brief This function get the length of a double list.
 *
 * @param list The list to get the length of.
 *
 * @return The length of the list.
 */
MDF_INLINE size_t mdf_list_get_length(struct mdf_list *list)
{
    size_t length = 0;
    struct mdf_list *node = list;

    while (node->next != list)
    {
        node = node->next;
        length++;
    }

    return length;
}

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* MDF_SERVICE_H */
